package com.zebra.gateway.processor;

import com.zebra.common.OfflineType;
import com.zebra.common.OnlineType;
import com.zebra.gateway.GwConfigInfoManager;
import com.zebra.gateway.protocol.GatewayCommand;
import com.zebra.gateway.protocol.GatewaySendMessageUtil;
import com.zebra.gateway.session.LoginSessionManager;
import com.zebra.gateway.session.Session;
import com.zebra.gateway.session.SessionManager;
import com.zebra.remoting.config.StateCode;
import com.zebra.remoting.connection.Connection;
import com.zebra.remoting.protocol.ProcessorType;
import com.zebra.remoting.util.RemotingUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
 *  网关 不知道进入游戏规则; 所以, 不做切换服务器, 还是由前端自己做操作
 */
public class ServerGameHandlerProcessor extends AbstractGatewayProcessor {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerGameHandlerProcessor.class);

    @Override
    public void doProcess(ChannelHandlerContext ctx, GatewayCommand msg) throws  Exception {
        ProcessorType processorType = msg.getProcessorType();
        switch (processorType){
            case GM:       { doGM(ctx, msg);       break;}
            case G_LOGIN:  { doG_LOGIN(ctx, msg); break;}
            case G_RECON:  { doG_RECON(ctx, msg); break;}  // 重连是断开了GW channel 重连链接
            case G_EXIT:   { doG_EXIT(ctx, msg);  break;}
            default:       { doGM(ctx, msg); }
        }
    }

    //进入游戏
    private void doG_LOGIN(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("GAME G_LOGIN {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
        if (msg.getUserId() < 1 || msg.getToken() < 1 || msg.getGameId() < 1){
            logger.error("GAME G_LOGIN TOKEN OR GameId is null {} {}", msg.toString(), RemotingUtil.channelToString(ctx.channel()));
            GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.ParamInvalid.code());
            return;
        }

        Session session = getSessionByServer(ctx, msg);
        if (null == session){
            return;
        }

        Connection tmsConnection = getTmsConnection(msg.getUserId(), msg.getToken(), msg.getCmd(), msg.getGameId(), ProcessorType.G_LOGIN);
        tmsConnection.getChannel().writeAndFlush(msg);
        session.setTempGid(msg.getGameId());
    }

    //重连游戏
    private void doG_RECON(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("GAME G_RECON {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
        if (msg.getUserId() < 1 || msg.getToken() < 1 || msg.getGameId() < 1){
            logger.error("GAME G_RECON TOKEN OR GameId is null {} {}", msg.toString(), RemotingUtil.channelToString(ctx.channel()));
            GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.ParamInvalid.code());
            return;
        }

        Session session = SessionManager.getInstance().getSession(msg.getUserId());
        if (null == session){
            // 如果重连异常 不能 发消息到 TMS 让其下线;  因为可能又正常玩家，顶掉了;
            logger.warn("Game G_RECON session is null uid:{}", msg.getUserId());
            Connection tmsConnection = getTmsConnection(msg.getUserId(), msg.getToken(), msg.getCmd(), msg.getGameId(), ProcessorType.G_RECON);
            tmsConnection.getChannel().writeAndFlush(msg);

            session = new Session(ctx.channel());
            session.setUserId(msg.getUserId());
            session.setGameId(msg.getGameId());
            LoginSessionManager.LOGINSESSION.putSession(session);
            return;
        }

        if (msg.getToken() != session.getToken() || msg.getGameId() != session.getGameId()){
            logger.error("GAME G_RECON SESSION not disagree 2  {} {};  stk {} sGameId {}",  RemotingUtil.channelToString(ctx.channel()), msg.toString(), session.getToken(), session.getGameId());
            GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.LoginUn.code());
            SessionManager.getInstance().removeBySession(session);
            GatewayProcessorUtil.sendTmsInactiveChannel(session, OfflineType.Reconn);
            return;
        }

        Connection gameConnection = getConnection(session, ProcessorType.G_RECON);
        // 如果重连异常 不能 发消息到 TMS 让其下线;  因为可能又正常玩家，顶掉了;
        gameConnection = null == gameConnection ? getTmsConnection(msg.getUserId(), msg.getToken(), msg.getCmd(), msg.getGameId(), ProcessorType.G_RECON) : gameConnection;
        gameConnection.getChannel().writeAndFlush(msg);

        session.setChannel(ctx.channel());
        LoginSessionManager.LOGINSESSION.putSession(session);

    }

    //返回大厅
    private void doG_EXIT(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("GAME G_EXIT {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
        if (msg.getToken() < 1){
            logger.error("GAME G_EXIT TOKEN is null {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
            GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.ParamInvalid.code());
            return;
        }

        forwardMessage(ctx, msg, ProcessorType.G_EXIT);

    }

    private void doGM(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("GAME GM {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
        if (msg.getToken() < 1){
            logger.error("GAME GM TOKEN is null {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
            GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.ParamInvalid.code());
            return;
        }
        forwardMessage(ctx, msg,  ProcessorType.GM);
    }

    private void forwardMessage(ChannelHandlerContext ctx, GatewayCommand msg, ProcessorType processorType)throws Exception{
        Session session = getSessionByServer(ctx, msg);
        if (null == session){
            return;
        }

       if (GwConfigInfoManager.getInstance().getGwServerInfo().getOnline() == OnlineType.OffLine.value()){
           GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.Success.code());
           return;
       }

        Connection connection = getConnection(session, processorType);
        if (null != connection){
            connection.writeAndFlush(msg);
        }else {
            GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.GameServerDowntime.code());
        }
    }



    private Connection getConnection(Session session, ProcessorType processorType){
        Connection connection = session.getGameConn();
        if (connection.isFine()){
            return connection;
        }
        Connection newConn = GwConfigInfoManager.getInstance().getTMSConnectionByRandom(connection.getServerId());
        if (null != newConn){
            sendSWITCHTMS(newConn, session, processorType);
            session.setGameConn(newConn);
            logger.warn("Game switch TMS connection; processorType: {}  u: {} gid: {} newConn: {} ", processorType, session.getUserId(), session.getGameId(), newConn.toString());
            return newConn;
        }
        logger.error("Game  Tms connection is null; processorType: {}  u: {} gid: {} sid: {} ", processorType, session.getUserId(), session.getGameId(), connection.getServerId());
        return null;
    }


}
